home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
utils
/
stcron3.lzh
/
COMMAND.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-03
|
6KB
|
264 lines
/* CROND & CRONTAB: (c) Kees Lemmens, Netherlands; June 1993.
Programs for ATARI ST (running under MINT) to make it possible
to run background jobs at regular intervals.
version 1.1: Okt 1993
- Spawned jobs get uid and gid from user who submitted them.
- Default directory is changed to users homedir.
(again on special request by Jeroen Berger !)
Any questions or suggestions about this program can be send to:
lemmens@dv.twi.tudelft.nl
*/
#include "cron.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include <signal.h>
#include <pwd.h>
#include <sys\wait.h>
extern void LogMsg(char *name, int pid, char *fmt,...);
extern char *ux2dos(char *);
char *environ[] = { "", NULL };
/* Environment is not read by Mintshel so it's in fact useless ! */
int sspawnve(int mode,char *cmd, char *argstring, char **envp)
{ char TosArgs[128] = "x";
int imode;
#ifdef DEBUG
mode = P_WAIT;
#endif
ux2dos(cmd);
ux2dos(argstring);
strncat(TosArgs,argstring,sizeof(TosArgs) - 1);
*TosArgs = strlen(argstring); /* first byte is strlen */
switch(mode)
{ case P_WAIT : imode= 0; break;
case P_NOWAIT : imode=100; break;
case P_OVERLAY : imode=200; break;
}
return (int)Pexec(imode, cmd, TosArgs, (void *)envp);
}
void WriteMailHeader(entry *job,FILE *fp)
{ time_t t;
time(&t);
/* first line conform mail headers under UNIX */
fprintf(fp,"From cron %s",ctime(&t));
fprintf(fp,"To: %s\n",job->User);
fprintf(fp,"Subject: Output from %s job\n\n",
job->Type == CRON ? "cron" : "at");
fprintf(fp,"Command: %s\n\n",job->Command);
fflush(fp);
}
int StartJob(entry *job,active *ajob)
{ char cmdstring[MAX_TEMPSTR];
static counter = 0; /* for unique filenames */
struct passwd *pwent;
FILE *fp;
int fd;
/* Use a unique filename for output. Tmpnam can't be used, as it
also generates $ signs that can confuse the shell !!
*/
#ifdef DEBUG
strcpy(ajob->Output,"u:/dev/tty");
#else
sprintf(ajob->Output,SPOOLDIR "/%08.8d.crn",counter++);
#endif
strcpy(ajob->User,job->User);
sprintf(cmdstring,"-c %s; %.*s",DEFPATH,MAX_COMMAND,job->Command);
if ((fp = fopen(ux2dos(ajob->Output),"w")) == NULL)
return EROUTP;
WriteMailHeader(job,fp);
/* redirect stdout and stderr */
fd=fileno(fp);
Fforce(1,fd); Fforce(2,fd);
{ if((ajob->Pid =(int)fork()) == 0)
{
/* must change uid & gid in a subprocess or it will
be impossible to change back to uid 0 again !
*/
if((pwent = getpwnam(job->User)) != NULL)
{ (void)setuid(pwent->pw_uid);
(void)setgid(pwent->pw_gid);
Dsetpath(ux2dos(pwent->pw_dir));
/* this assumes we're in drive u: */
}
sspawnve(P_OVERLAY,SHELLCMD,cmdstring,environ);
exit(1); /* just in case Pexec overlay fails */
}
}
if(ajob->Pid < 0)
{ Fforce(1,0); Fforce(2,0);
fclose(fp);
return ERJOB;
}
ajob->Status = BUSY;
Fforce(1,0); Fforce(2,0);
fclose(fp);
return ajob->Pid;
}
void HandleExits(active ajobs[])
{ int nr;
FILE *fp;
char cmdstring[MAX_COMMAND];
union
{ long l;
struct { int Pid; int ExitCode; } c;
} stat;
/* collect all finished jobs */
while((stat.l=Pwait3(WNOHANG,NULL)) > 0L)
{
for(nr=0;nr<MAX_SIMJOBS;nr++)
{ if(ajobs[nr].Pid == stat.c.Pid && ajobs[nr].Status == BUSY)
{
LogMsg(PROGNAME,stat.c.Pid,"Job finished (exit=%d)",
stat.c.ExitCode);
/* append exitcode to mail message */
if ((fp = fopen(ux2dos(ajobs[nr].Output),"a")) != NULL)
{ fprintf(fp,"\nExit code : %d\n",stat.c.ExitCode);
fclose(fp);
}
else
LogMsg(PROGNAME,stat.c.Pid,"Can't append to output %s",
ajobs[nr].Output);
ajobs[nr].Status = FINISHED;
}
}
}
/* send output from finished jobs as mail to the user */
#ifndef DEBUG
for(nr=0;nr<MAX_SIMJOBS;nr++)
{
if(ajobs[nr].Status != FINISHED)
continue;
sprintf(cmdstring,"-c " MAILCMD " " MAILARG,
ajobs[nr].Output,ajobs[nr].User);
sspawnve(P_WAIT,SHELLCMD,cmdstring,environ);
/* and AFTER that (!!) remove the outputfile */
if(remove(ajobs[nr].Output) != 0)
LogMsg(PROGNAME,stat.c.Pid,"Can't remove output %s",
ajobs[nr].Output);
ajobs[nr].Status = FREE; /* clear status */
}
#endif
}
void RemoveAtJob(entry *job)
{ char atfile[MAX_FNAME];
sprintf(atfile,"%s/%s.%03d",ATDIR,job->User,job->AtId);
if(remove(ux2dos(atfile)) < 0)
LogMsg(PROGNAME, getpid(), "Can't remove %s",atfile);
}
void DoJobs(entry joblist[], int jobcount, active ajoblist[])
{ int x,n,chpid,cmd;
int cronout;
char *message;
for(x=0;x<jobcount;x++)
{
if(joblist[x].Status == START)
{
for(n=0;n<MAX_SIMJOBS && ajoblist[n].Status != FREE;n++);
/* If no more jobs then don't clear job Status so we'll
retry next run.
*/
if(n>=MAX_SIMJOBS)
{ LogMsg(PROGNAME,getpid(),"No more active jobs \"%.10s\" (%s)",
joblist[n].Command,joblist[n].User);
return;
}
chpid = StartJob(&joblist[x],&ajoblist[n]);
switch(chpid)
{ case EROUTP:
message="%Job \".15s\" (%s) no output";
break;
case ERJOB:
message="%Job \".15s\" (%s) failed";
break;
default:
joblist[x].Status = SLEEP;
switch(joblist[x].Type)
{ case CRON :
message="CRON job \"%.10s\" (%s) started";
break;
case AT :
message="AT job \"%.10s\" (%s) started";
/* job can be removed: only one run */
if((cronout=open(CRONPIPE,O_WRONLY)) < 0)
LogMsg(PROGNAME,getpid(),
"Internal write to pipe failed");
else
{ cmd = INTERNBUILD;
write(cronout,&cmd,1);
close(cronout);
}
RemoveAtJob(&joblist[x]);
break;
}
break;
}
LogMsg(PROGNAME,chpid,message,joblist[x].Command,
joblist[x].User);
#ifdef DEBUG
DebugPrintTimes(&joblist[x]);
#endif
}
}
}